﻿/*  
	========================================================================
	 awzBoxes Library
	
	 Homepage: http://www.awzhome.de/
	========================================================================
	
	This Source Code Form is subject to the terms of the Mozilla Public
	License, v. 2.0. If a copy of the MPL was not distributed with this
	file, You can obtain one at http://mozilla.org/MPL/2.0/.
   
	The Original Code is code of awzBoxes Library.

	The Initial Developer of the Original Code is Andreas Weizel.
	Portions created by the Initial Developer are
	Copyright (C) 2011-2012 Andreas Weizel. All Rights Reserved.
	
	Contributor(s): (none)
	
	========================================================================
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace AWZhome.awzBoxes.Tools
{
	/// <summary>
	/// A partially transparent area drawn over a Box, when a BoxItem is dragged over it.
	/// </summary>
	public partial class DragOverlayBox : UserControl
	{

		#region Dependency properties

		public static readonly DependencyProperty AllowOuterRightDropProperty =
			DependencyProperty.Register("AllowOuterRightDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowInnerRightDropProperty =
			DependencyProperty.Register("AllowInnerRightDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowInnerLeftDropProperty =
			DependencyProperty.Register("AllowInnerLeftDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowOuterLeftDropProperty =
			DependencyProperty.Register("AllowOuterLeftDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowOuterBottomDropProperty =
			DependencyProperty.Register("AllowOuterBottomDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowInnerBottomDropProperty =
			DependencyProperty.Register("AllowInnerBottomDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowInnerDropProperty =
			DependencyProperty.Register("AllowInnerDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowInnerTopDropProperty =
			DependencyProperty.Register("AllowInnerTopDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));
		public static readonly DependencyProperty AllowOuterTopDropProperty =
			DependencyProperty.Register("AllowOuterTopDrop", typeof(bool), typeof(DragOverlayBox), new UIPropertyMetadata(true));

		#endregion

		public DragOverlayBox()
		{
			InitializeComponent();
			this.InnerGrid.DataContext = this;
		}

		public bool AllowOuterTopDrop
		{
			get
			{
				return (bool) GetValue(AllowOuterTopDropProperty);
			}
			set
			{
				SetValue(AllowOuterTopDropProperty, value);
			}
		}

		public bool AllowInnerTopDrop
		{
			get
			{
				return (bool) GetValue(AllowInnerTopDropProperty);
			}
			set
			{
				SetValue(AllowInnerTopDropProperty, value);
			}
		}

		public bool AllowInnerDrop
		{
			get
			{
				return (bool) GetValue(AllowInnerDropProperty);
			}
			set
			{
				SetValue(AllowInnerDropProperty, value);
			}
		}

		public bool AllowInnerBottomDrop
		{
			get
			{
				return (bool) GetValue(AllowInnerBottomDropProperty);
			}
			set
			{
				SetValue(AllowInnerBottomDropProperty, value);
			}
		}

		public bool AllowOuterBottomDrop
		{
			get
			{
				return (bool) GetValue(AllowOuterBottomDropProperty);
			}
			set
			{
				SetValue(AllowOuterBottomDropProperty, value);
			}
		}

		public bool AllowOuterLeftDrop
		{
			get
			{
				return (bool) GetValue(AllowOuterLeftDropProperty);
			}
			set
			{
				SetValue(AllowOuterLeftDropProperty, value);
			}
		}

		public bool AllowInnerLeftDrop
		{
			get
			{
				return (bool) GetValue(AllowInnerLeftDropProperty);
			}
			set
			{
				SetValue(AllowInnerLeftDropProperty, value);
			}
		}

		public bool AllowInnerRightDrop
		{
			get
			{
				return (bool) GetValue(AllowInnerRightDropProperty);
			}
			set
			{
				SetValue(AllowInnerRightDropProperty, value);
			}
		}

		public bool AllowOuterRightDrop
		{
			get
			{
				return (bool) GetValue(AllowOuterRightDropProperty);
			}
			set
			{
				SetValue(AllowOuterRightDropProperty, value);
			}
		}

		private void UserControl_DragEnter(object sender, DragEventArgs e)
		{
			if (e.Data.GetFormats().Contains(Box.BoxItemDragDropFormat))
			{
				Image targetImage = ControlFinder.FindAncestor<Image>((DependencyObject) e.OriginalSource);
				if (targetImage != null)
				{
					// Create a hover effect by increasing the image by 20%
					Grid.SetZIndex(targetImage, 99);
					targetImage.RenderTransform =
						new ScaleTransform(1.2, 1.2, targetImage.Width / 2, targetImage.Height / 2);

					this.SetContainerBorder(targetImage, true);
				}
			}
		}

		private void UserControl_DragLeave(object sender, DragEventArgs e)
		{
			if (e.Data.GetFormats().Contains(Box.BoxItemDragDropFormat))
			{
				Image targetImage = ControlFinder.FindAncestor<Image>((DependencyObject) e.OriginalSource);
				if (targetImage != null)
				{
					// Reset hover effect
					Grid.SetZIndex(targetImage, 0);
					targetImage.RenderTransform = null;

					this.SetContainerBorder(targetImage, false);
				}
			}
		}

		private void UserControl_Drop(object sender, DragEventArgs e)
		{
			if (e.Data.GetFormats().Contains(Box.BoxItemDragDropFormat))
			{
				BoxItem sourceBoxItem = e.Data.GetData(Box.BoxItemDragDropFormat) as BoxItem;
				Image targetImage = ControlFinder.FindAncestor<Image>((DependencyObject) e.OriginalSource);
				if (targetImage != null)
				{
					// Reset hover effect
					Grid.SetZIndex(targetImage, 0);
					targetImage.RenderTransform = null;

					this.SetContainerBorder(targetImage, false);
					this.DropBoxItem(targetImage, sourceBoxItem);
					sourceBoxItem.IsActive = true;
				}
			}
		}

		private void SetContainerBorder(Image targetImage, bool showBorder)
		{
			Box parentBox = this.DataContext as Box;
			if (parentBox != null)
			{
				// Handle inner drop areas
				if (targetImage == this.TopDropArea)
				{
					parentBox.HighlightTopBorder = showBorder;
				}
				else if (targetImage == this.BottomDropArea)
				{
					parentBox.HighlightBottomBorder = showBorder;
				}
				else if (targetImage == this.LeftDropArea)
				{
					parentBox.HighlightLeftBorder = showBorder;
				}
				else if (targetImage == this.InnerDropArea)
				{
					parentBox.HighlightTopBorder = showBorder;
					parentBox.HighlightBottomBorder = showBorder;
					parentBox.HighlightLeftBorder = showBorder;
					parentBox.HighlightRightBorder = showBorder;
				}
				else if (targetImage == this.RightDropArea)
				{
					parentBox.HighlightRightBorder = showBorder;
				}

				// Handle outer drop areas
				BoxLine parentBoxLine = parentBox.ParentBoxLine;
				if (parentBoxLine != null)
				{
					BoxArea parentBoxArea = parentBoxLine.ParentBoxArea;
					if (parentBoxArea != null)
					{
						BoxWindowContainer parentBoxWindowContainer = parentBoxArea.ParentBoxWindowContainer;
						if (parentBoxWindowContainer != null)
						{
							if (targetImage == this.OuterTopDropArea)
							{
								if ((parentBoxWindowContainer.TopBoxArea != null) && (parentBoxWindowContainer.TopBoxArea.BoxLines.Count > 0))
								{
									parentBoxWindowContainer.TopBoxArea.HighlightTopBorder = showBorder;
									parentBoxWindowContainer.TopBoxArea.HighlightBottomBorder = showBorder;
									parentBoxWindowContainer.TopBoxArea.HighlightLeftBorder = showBorder;
									parentBoxWindowContainer.TopBoxArea.HighlightRightBorder = showBorder;
								}
								else
								{
									parentBoxArea.HighlightTopBorder = showBorder;
								}
							}
							else if (targetImage == this.OuterBottomDropArea)
							{
								if ((parentBoxWindowContainer.BottomBoxArea != null) && (parentBoxWindowContainer.BottomBoxArea.BoxLines.Count > 0))
								{
									parentBoxWindowContainer.BottomBoxArea.HighlightTopBorder = showBorder;
									parentBoxWindowContainer.BottomBoxArea.HighlightBottomBorder = showBorder;
									parentBoxWindowContainer.BottomBoxArea.HighlightLeftBorder = showBorder;
									parentBoxWindowContainer.BottomBoxArea.HighlightRightBorder = showBorder;
								}
								else
								{
									parentBoxArea.HighlightBottomBorder = showBorder;
								}
							}
							else if (targetImage == this.OuterLeftDropArea)
							{
								if ((parentBoxWindowContainer.LeftBoxArea != null) && (parentBoxWindowContainer.LeftBoxArea.BoxLines.Count > 0))
								{
									parentBoxWindowContainer.LeftBoxArea.HighlightTopBorder = showBorder;
									parentBoxWindowContainer.LeftBoxArea.HighlightBottomBorder = showBorder;
									parentBoxWindowContainer.LeftBoxArea.HighlightLeftBorder = showBorder;
									parentBoxWindowContainer.LeftBoxArea.HighlightRightBorder = showBorder;
								}
								else
								{
									parentBoxArea.HighlightLeftBorder = showBorder;
								}
							}
							else if (targetImage == this.OuterRightDropArea)
							{
								if ((parentBoxWindowContainer.RightBoxArea != null) && (parentBoxWindowContainer.RightBoxArea.BoxLines.Count > 0))
								{
									parentBoxWindowContainer.RightBoxArea.HighlightTopBorder = showBorder;
									parentBoxWindowContainer.RightBoxArea.HighlightBottomBorder = showBorder;
									parentBoxWindowContainer.RightBoxArea.HighlightLeftBorder = showBorder;
									parentBoxWindowContainer.RightBoxArea.HighlightRightBorder = showBorder;
								}
								else
								{
									parentBoxArea.HighlightRightBorder = showBorder;
								}
							}
						}
					}
				}
			}
		}

		private void DropBoxItem(Image targetImage, BoxItem sourceBoxItem)
		{
			Box parentBox = this.DataContext as Box;
			if (parentBox != null)
			{
				if (targetImage == this.InnerDropArea)
				{
					// Only allow to drag a BoxItem to inner drop area of another Box (not its own)
					if (sourceBoxItem.ParentBox != parentBox)
					{
						// Delete the BoxItem from its former container
						if (sourceBoxItem.ParentBox != null)
						{
							sourceBoxItem.ParentBox.Items.Remove(sourceBoxItem);
						}

						// Now add to new target container Box
						parentBox.Items.Add(sourceBoxItem);
					}

					return;
				}

				BoxLine parentBoxLine = parentBox.ParentBoxLine;
				if (parentBoxLine != null)
				{
					BoxArea parentBoxArea = parentBoxLine.ParentBoxArea;
					if (parentBoxArea != null)
					{
						// Delete the BoxItem from its former container
						if (sourceBoxItem.ParentBox != null)
						{
							sourceBoxItem.ParentBox.Items.Remove(sourceBoxItem);
						}

						// Move to new container
						if (targetImage == this.TopDropArea)
						{
							// Create new BoxLine over the current one
							BoxLine newBoxLine = new BoxLine();
							Box newBox = new Box();
							parentBoxArea.BoxLines.Insert(parentBoxArea.BoxLines.IndexOf(parentBoxLine), newBoxLine);
							newBoxLine.Boxes.Add(newBox);
							newBox.Items.Add(sourceBoxItem);
						}
						else if (targetImage == this.BottomDropArea)
						{
							// Create new BoxLine under the current one
							BoxLine newBoxLine = new BoxLine();
							Box newBox = new Box();
							parentBoxArea.BoxLines.Insert(parentBoxArea.BoxLines.IndexOf(parentBoxLine) + 1, newBoxLine);
							newBoxLine.Boxes.Add(newBox);
							newBox.Items.Add(sourceBoxItem);
						}
						else if (targetImage == this.LeftDropArea)
						{
							// We create a new Box on the left
							Box newBox = new Box();
							parentBoxLine.Boxes.Insert(parentBoxLine.Boxes.IndexOf(parentBox), newBox);
							newBox.Items.Add(sourceBoxItem);
						}
						else if (targetImage == this.RightDropArea)
						{
							// We create a new Box on the right
							Box newBox = new Box();
							parentBoxLine.Boxes.Insert(parentBoxLine.Boxes.IndexOf(parentBox) + 1, newBox);
							newBox.Items.Add(sourceBoxItem);
						}

						BoxWindowContainer parentBoxWindowContainer = parentBoxArea.ParentBoxWindowContainer;
						if (parentBoxWindowContainer != null)
						{
							BoxArea sideBoxArea = null;

							if (targetImage == this.OuterTopDropArea)
							{
								// Add the BoxItem to top side area
								if (parentBoxWindowContainer.TopBoxArea != null)
								{
									sideBoxArea = parentBoxWindowContainer.TopBoxArea;
								}
							}
							else if (targetImage == this.OuterBottomDropArea)
							{
								// Add the BoxItem to bottom side area
								if (parentBoxWindowContainer.BottomBoxArea != null)
								{
									sideBoxArea = parentBoxWindowContainer.BottomBoxArea;
								}
							}
							else if (targetImage == this.OuterLeftDropArea)
							{
								// Add the BoxItem to left side area
								if (parentBoxWindowContainer.LeftBoxArea != null)
								{
									sideBoxArea = parentBoxWindowContainer.LeftBoxArea;
								}
							}
							else if (targetImage == this.OuterRightDropArea)
							{
								// Add the BoxItem to right side area
								if (parentBoxWindowContainer.RightBoxArea != null)
								{
									sideBoxArea = parentBoxWindowContainer.RightBoxArea;
								}
							}

							if (sideBoxArea != null)
							{
								// Add new BoxLine, if not existing
								if (sideBoxArea.BoxLines.Count == 0)
								{
									sideBoxArea.BoxLines.Add(new BoxLine());
								}
								// Add new Box, if not existing
								BoxLine sideBoxLine = sideBoxArea.BoxLines[0];
								if (sideBoxLine.Boxes.Count == 0)
								{
									sideBoxLine.Boxes.Add(new Box());
								}
								// Add the BoxItem to first Box
								sideBoxLine.Boxes[0].Items.Add(sourceBoxItem);
							}
						}
					}
				}
			}
		}
	}
}
